package com.haima.sage.bigdata.api.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.haima.sage.bigdata.api.common.AESUtils;
import com.haima.sage.bigdata.api.common.CacheUtils;
import com.haima.sage.bigdata.api.common.Constants;
import com.haima.sage.bigdata.api.common.SignUtils;
import com.haima.sage.bigdata.api.entity.AppSystem;
import com.haima.sage.bigdata.api.entity.auditlog.ApiType;
import com.haima.sage.bigdata.api.entity.auditlog.AuditLog;
import com.haima.sage.bigdata.api.entity.auditlog.OperateType;
import com.haima.sage.bigdata.api.service.AuditLogService;
import com.haima.sage.bigdata.api.vo.Result;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.util.Date;
import java.util.List;
import java.util.Map;

public class BaseController {
    private static final Logger LOG = LogManager.getLogger(BaseController.class);

    @Value("${com.haima.bigdata.query.api.time.limit}")
    protected Long timeLimit;
    @Value("${com.haima.bigdata.query.api.aes.enable}")
    protected Boolean aesEnable;
    @Autowired
    protected final AuditLogService auditLogService;

    public BaseController(AuditLogService auditLogService) {
        this.auditLogService = auditLogService;
    }

    protected boolean validSign(String secret, String requestURI, Map<String, ?> params, String appKey, Long timestamp, String sign, String userId, String userName) {
        String raw = SignUtils.makeGetRaw(secret, requestURI, params, appKey, userId, userName, timestamp);
        String md5 = SignUtils.digest(raw);
        if (md5.equals(sign)) {
            return true;
        }
        LOG.error("md5 not equals sign");
        if (LOG.isDebugEnabled()) {
            LOG.debug("sign raw:{}, md5:{}, sign:{}", raw, md5, sign);
        }
        return false;
    }

    protected boolean validSign(String secret, String requestURI, String body, String sign) {
        String raw = SignUtils.makeNotGetRaw(secret, requestURI, body);
        String md5 = SignUtils.digest(raw);
        if (md5.equals(sign)) {
            return true;
        }
        LOG.error("md5 not equals sign");
        if (LOG.isDebugEnabled()) {
            LOG.debug("sign raw:{}, md5:{}, sign:{}", raw, md5, sign);
        }
        return false;
    }

    protected ResponseEntity<String> error(HttpStatus status, String msg, String subMsg) {
        Result result = new Result("" + status.value(), msg, subMsg);
        String tmp = format(Constants.DEFAULT_FORMAT, result);
        return new ResponseEntity<>(tmp, HttpStatus.OK); // status
    }

    protected ResponseEntity<String> ok(String msg, String subMsg, Object data) {
        Result result = new Result(Constants.SUCCESS_STATUS, msg, subMsg, data);
        String tmp = format(Constants.DEFAULT_FORMAT, result);
        return new ResponseEntity<>(tmp, HttpStatus.OK);
    }

    protected ResponseEntity<String> ok(Object data) {
        Result result = new Result(Constants.SUCCESS_STATUS, data);
        String tmp = format(Constants.DEFAULT_FORMAT, result);
        return new ResponseEntity<>(tmp, HttpStatus.OK);
    }

    protected String format(String format, Result result) {
        ObjectMapper mapper;
        if (Constants.FORMAT_XML.equalsIgnoreCase(format)) {
            mapper = new XmlMapper();
            try {
                return mapper.writeValueAsString(result);
            } catch (JsonProcessingException e) {
                return "";
            }
        } else {
            mapper = new ObjectMapper();
            try {
                return mapper.writeValueAsString(result);
            } catch (JsonProcessingException e) {
                return "";
            }
        }

    }

    protected void addAuditLog(String appKey, String appName, ApiType type,
                               OperateType result, String name, String content,
                               String userId, String userName) {
        AuditLog auditLog = new AuditLog();
        auditLog.setAppId(appKey);
        auditLog.setAppName(appName);
        auditLog.setType(type);
        auditLog.setSubType(result);
        auditLog.setContent(content);
        auditLog.setName(name);
        auditLog.setUserId(userId);
        auditLog.setUserName(userName);
        auditLog.setCreateDate(new Date());
        this.auditLogService.save(auditLog);
    }

    protected ResponseEntity<String> validateBase(String appkey, String appUserId, String appUserName, Long timestamp) {
        if (timestamp == null) {
            return error(HttpStatus.BAD_REQUEST, Constants.TIME_EMPTY_ERROR_EN,
                    Constants.TIME_EMPTY_ERROR_CN);
        }
        if (appUserId == null) {
            return error(HttpStatus.BAD_REQUEST, Constants.APP_USER_ID_EMPTY_ERROR_EN,
                    Constants.APP_USER_ID_EMPTY_ERROR_CN);
        }
        if (appUserName == null) {
            return error(HttpStatus.BAD_REQUEST, Constants.APP_USER_NAME_EMPTY_ERROR_EN,
                    Constants.APP_USER_NAME_EMPTY_ERROR_CN);
        }
        if (appkey == null) {
            return error(HttpStatus.BAD_REQUEST, Constants.APP_KEY_EMPTY_ERROR_EN,
                    Constants.APP_KEY_EMPTY_ERROR_CN);
        }
        if (System.currentTimeMillis() - timestamp > timeLimit) {
            return error(HttpStatus.BAD_REQUEST, Constants.TIME_ERROR_EN,
                    Constants.TIME_ERROR_CN);
        }
        return null;
    }

    public String getStringValue(Map<?, ?> map, String key) {
        Object obj = map.get(key);
        if (obj == null) {
            return null;
        }
        return obj.toString();
    }

    public Long getLongValue(Map<?, ?> map, String key) {
        Object obj = map.get(key);
        if (obj == null) {
            return null;
        }
        try {
            return Long.parseLong(obj.toString());
        } catch (Exception e) {
            return null;
        }
    }

    public AppSystem getAppSystem(String appkey, List<AppSystem> systems) throws Exception {
        if (systems != null && systems.size() > 0) {
            for (AppSystem bs : systems) {
                if (appkey.equals(bs.getId())) {
                    decryptSecret(bs);
                    return bs;
                }
            }
        }
        return null;
    }

    public void decryptSecret(AppSystem bs) throws Exception {
        if (aesEnable) {
            String value = CacheUtils.getCache(bs.getSecret());
            if (value == null) {
                value = AESUtils.decrypt(bs.getSecret(), Constants.AES_KEY);
                CacheUtils.setCache(bs.getSecret(), value);
            }
            bs.setSecret(value);
        }
    }
}
